﻿using UnityEngine;
using System.Collections;

/// <summary>
/// <para>Controls every Input Events.</para>
/// <para>OnTouchTap    -> On a mouse click or a touch tap</para>
/// <para>OnTouchEnter  -> As soon as it begins a touch on an object</para>
/// <para>OnTouchStay   -> When the mouse is down on the entered object</para>
/// <para>OnTouchExit   -> When the mouse is released on the entered object</para>
/// <para>OnTouchDown   -> When the mouse begins a touch (Callback) </para>
/// <para>OnTouchUp     -> When the mouse is released (CallBack)</para>
/// </summary>
public class InputManager : Singleton<InputManager> 
{
    public float            m_ClickThreshold;
    public float            m_ClickTime;
    public float            m_DoubleClickTime;
    public Transform        m_MousePositionTransform;

    private Vector3         m_MouseToScreenPosition;
    public Vector3          MouseToScreenPosition
    {
        get { return m_MouseToScreenPosition; }
    }

    private Vector3         m_MousePosition;
    private Ray             m_MouseRay;
    private RaycastHit      m_RayHitInfo; 
    private RaycastHit      m_PreviousRayHitInfo; 
    private Rect            m_ScreenLimit;

    private Vector2         m_ScreenSize;
    private Collider        m_CurrentObjectTouched;
    private Vector2         m_EnterTouchPosition;

    private float           m_ClickTimer;

    public delegate void    Callback();
    public static Callback  m_OnWindowResize;
    public static Callback  OnTouchDown;
    public static Callback  OnTouchUp;
    
    protected override void Awake()
    {
        base.Awake();
        
        m_ScreenLimit = new Rect(0,0, Screen.width, Screen.height);
        m_ScreenSize = new Vector2(Screen.width, Screen.height);

        m_CurrentObjectTouched = null;
        m_ClickTimer = m_ClickTime;

        m_OnWindowResize += OnWindowResize;
    }
	
	private void Update () 
    {        
        m_MouseToScreenPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        if (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsEditor)
        {     
            if (m_ScreenLimit.Contains(Input.mousePosition))
            {   
                m_MouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
                if(Input.GetMouseButtonDown(0))
                {
                    if(OnTouchDown != null) OnTouchDown();
                }

                Debug.DrawRay(Camera.main.transform.position, m_MouseRay.direction, Color.cyan);
                if (Physics.Raycast(m_MouseRay, out m_RayHitInfo))
                {
                    m_RayHitInfo.transform.gameObject.SendMessage("OnTouchOver", SendMessageOptions.DontRequireReceiver);

                    if(Input.GetMouseButtonDown(0))
                    {
                        if(m_CurrentObjectTouched == null)
                        {
                            m_CurrentObjectTouched = m_RayHitInfo.collider;
                            m_EnterTouchPosition = new Vector2(m_MouseRay.direction.x, m_MouseRay.direction.y);
                            m_RayHitInfo.transform.gameObject.SendMessage("OnTouchEnter", SendMessageOptions.DontRequireReceiver);
                            m_ClickTimer = 0;
                        }
                    }

                    if (Input.GetMouseButton(0)) 
                    {
                        if(m_CurrentObjectTouched == m_RayHitInfo.collider)
                        {
                            m_RayHitInfo.transform.gameObject.SendMessage("OnTouchStay", SendMessageOptions.DontRequireReceiver);
                        }
                    }
                    m_PreviousRayHitInfo = m_RayHitInfo;
                }
                
                if (!Input.GetMouseButton(0)) 
                {
                    if(m_CurrentObjectTouched != null)
                    {
                        m_CurrentObjectTouched.gameObject.SendMessage("OnTouchReleased", SendMessageOptions.DontRequireReceiver);

                        if(m_CurrentObjectTouched == m_RayHitInfo.collider)
                        {
                            m_PreviousRayHitInfo.transform.gameObject.SendMessage("OnTouchExit", SendMessageOptions.DontRequireReceiver);

                            Vector2 mousePercentage = new Vector2(m_MouseRay.direction.x, m_MouseRay.direction.y);

                            if(Vector2.Distance(m_EnterTouchPosition, mousePercentage) < m_ClickThreshold && m_ClickTimer < m_ClickTime)
                            {
                                m_PreviousRayHitInfo.transform.gameObject.SendMessage("OnTouchTap", SendMessageOptions.DontRequireReceiver);
                            }
                            //Debug.Log("INITIAL = " + m_EnterTouchPosition.ToString() + " | CURRENT = " + mousePercentage.ToString());
                        }
                        
                        m_CurrentObjectTouched = null;
                    }
                }
            }
            //else
            //{
            //    if(m_CurrentObjectTouched != null)
            //    {
            //        //m_CurrentObjectTouched.gameObject.SendMessage("OnTouchReleased", SendMessageOptions.DontRequireReceiver);
            //    }
            //}
            
            if(Input.GetMouseButtonUp(0))
            {
                if(OnTouchUp != null) OnTouchUp();
            }
        }
        // TODO Touch Inputs
        else if(Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer)
        {
            if (m_ScreenLimit.Contains(Input.mousePosition))
            {   
                m_MouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
                if (Physics.Raycast(m_MouseRay, out m_RayHitInfo)) 
                {
                    for (int i = 0; i < Input.touchCount; ++i) 
                    {
                        Touch touch = Input.GetTouch(i);
                        Debug.DrawRay(Camera.main.transform.position, m_MouseRay.direction, Color.cyan);
                        
                        if (touch.phase.Equals(TouchPhase.Began)) 
                        {
                            m_RayHitInfo.transform.gameObject.SendMessage("OnTouchDown", SendMessageOptions.DontRequireReceiver);
                        }
                        else if(touch.phase.Equals(TouchPhase.Stationary) || touch.phase.Equals(TouchPhase.Moved)) 
                        {
                            m_RayHitInfo.transform.gameObject.SendMessage("OnTouchStay", SendMessageOptions.DontRequireReceiver);
                        }
                    }
                }
            }
        }

        m_MousePositionTransform.position = m_MouseRay.direction;
        m_ClickTimer += Time.deltaTime;
	}

    private void LateUpdate()
    {
        if(m_ScreenSize.x != Screen.width || m_ScreenSize.y != Screen.height)
        {
            if(m_OnWindowResize != null) m_OnWindowResize();
        }
        
        m_ScreenSize.x = Screen.width;
        m_ScreenSize.y = Screen.height;
    }

    private void OnWindowResize()
    {
        Debug.Log("WINDOW RESIZED");
        m_ScreenLimit = new Rect(0,0, Screen.width, Screen.height);
    }
}
